/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package xenon3d.vector;

/**
 * This class represents a vector in 4 dimensional floating point vector space.
 * @author Volker Everts
 * @version 0.1 - 19.08.08: Created
 */
public class Vector4f extends Point4f {

    // <editor-fold defaultstate="collapsed" desc=" Static Attributes ">

    /** The serial version UID. */
    private static final long serialVersionUID = 20110917L;

    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc=" Initialization ">

    /**
     * Creates a new Vector3f with the coordinates (0, 0, 0, 0).
     */
    public Vector4f() {
        super();
    }

    /**
     * Creates a new Vector4f using the specified coordinates.
     * @param x the x coordinate
     * @param y the y coordinate
     * @param z the z coordinate
     * @param w the w coordinate
     */
    public Vector4f(float x, float y, float z, float w) {
        super(x, y, z, w);
    }

    /**
     * Creates a new Vector4f with the same coordinates as the specified other
     * tuple, point or vector.
     * @param t the other tuple
     */
    public Vector4f(Tuple4f t) {
        super(t);
    }

    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc=" Public Methods ">

    /**
     * Inverts this vector in place. Alias method for negate().
     */
    public final void invert() {
        x = -x;
        y = -y;
        z = -z;
        w = -w;
    }

    /**
     * Sets the value of this vector to the inversion of the specified vector.
     * Alias method for negate(Vector3f).
     * @param v the other vector
     */
    public final void invert(Vector4f v) {
        x = -v.x;
        y = -v.y;
        z = -v.z;
        w = -v.w;
    }

    /**
     * Normalizes this vector in place.
     */
    public final void normalize() {
        float norm = lengthSq();
        if (FMath.isEqual(norm, 1.0f, FMath.EPS)) return;
        if (norm > FMath.EPS) {
            norm = FMath.sqrt(norm);
            x /= norm;
            y /= norm;
            z /= norm;
            w /= norm;
        }
        else set(0.0f, 0.0f, 0.0f, 0.0f);
    }

    /**
     * Sets the value of this vector to the normalization of the specified vector.
     * @param v the other vector
     */
    public final void normalize(Vector4f v) {
        set(v);
        normalize();
    }

    /**
     * Returns the length of this vector.
     * @return the length of this vector
     */
    public final float length() {
        return FMath.sqrt(x * x + y * y + z * z + w * w);
    }

    /**
     * Returns the squared length of this vector.
     * @return the squared length
     */
    public final float lengthSq() {
        return x * x + y * y + z * z + w * w;
    }

    /**
     * Returns the inner product of this vector and another vector or point,
     * given by its x,y,z,w coordinates.
     * @param x the other point's x coordinate
     * @param y the other point's y coordinate
     * @param z the other point's z coordinate
     * @param w the other point's w coordinate
     * @return the dot product
     */
    public final float dot(float x, float y, float z, float w) {
        return this.x * x + this.y * y + this.z * z + this.w * w;
    }

    /**
     * Returns the inner product of this vector and another vector or point.
     * @param p the other vector (or point)
     * @return the dot product
     */
    public final float dot(Point4f p) {
        return x * p.x + y * p.y + z * p.z + w * p.w;
    }

    /**
     * Returns the angle between this vector and another vector.
     * @param v the other vector
     * @return the angle between this vector and the other vector
     */
    public final float angle(Vector4f v) {
        float cos = dot(v) / FMath.sqrt(lengthSq() * v.lengthSq());
        if (cos < -1.0f) cos = -1.0f;
        else if (cos > 1.0f) cos = 1.0f;
        return FMath.acos(cos);
    }

    // </editor-fold>

} // end class Vector4f